package server

import (
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"strings"
	"time"

	"backend/internal/common"
	"backend/internal/dao"
	"backend/internal/handlers"
	"backend/pkg/webrtc"

	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/cors"
	"github.com/gofiber/fiber/v2/middleware/logger"
	"github.com/gofiber/websocket/v2"
	"github.com/pelletier/go-toml"
	"github.com/redis/go-redis/v9"
)

var (
	cert = flag.String("cert", "", "")
	key  = flag.String("key", "", "")

	RDB *redis.Client
	Ctx = context.Background()
)

func Run() error {
	flag.Parse()
	initMap()
	config := initToml()
	// dao.InitDatabase(config)
	// initRedis(config)
	app := fiber.New(fiber.Config{})
	app.Use(logger.New())
	app.Use(cors.New())

	app.Get("/caller/websocket", BrowserMiddleware(config), websocket.New(handlers.CallerConn, websocket.Config{
		HandshakeTimeout: 10 * time.Second,
	}))
	app.Get("/callee/websocket", DeviceMiddleware(config), websocket.New(handlers.CalleeConn, websocket.Config{
		HandshakeTimeout: 10 * time.Second,
	}))
	// app.Get("/getinfo", AuthMiddleware(config), func(c *fiber.Ctx) error {
	// 	return handlers.GetInfo(c, dao.DB)
	// })
	// app.Post("/login", func(c *fiber.Ctx) error {
	// 	return handlers.Login(c, dao.DB, RDB, config)
	// })
	// app.Post("/register", func(c *fiber.Ctx) error {
	// 	return handlers.Register(c, dao.DB, config)
	// })

	if *cert != "" {
		return app.ListenTLS(config.Get("env.PORT").(string), *cert, *key)
	}
	return app.Listen(fmt.Sprintf("%s:%s", config.Get("env.HOST"), config.Get("env.PORT").(string)))
}

func initToml() *toml.Tree {
	// 读取配置文件
	config, err := toml.LoadFile("fly.toml")
	if err != nil {
		panic("failed to load config")
	}
	return config
}

func initMap() {
	webrtc.Rooms = make(map[string]*webrtc.Room)
	webrtc.Peers = make(map[*webrtc.PeerConnectionState]*webrtc.Room)
}

func initRedis(config *toml.Tree) {
	opt, err := redis.ParseURL(config.Get("env.REDIS_URL").(string))
	if err != nil {
		panic(err)
	}

	RDB = redis.NewClient(opt)
	if err := RDB.Ping(Ctx).Err(); err != nil {
		panic("Failed to connect Redis: " + err.Error())
	}
	println("Redis connected")
}

func AuthMiddleware(config *toml.Tree) func(c *fiber.Ctx) error {
	return func(c *fiber.Ctx) error {
		token := ""
		if strings.Contains(strings.ToLower(c.Get("Connection")), "upgrade") &&
			strings.ToLower(c.Get("Upgrade")) == "websocket" {
			// 是 WebSocket
			token = c.Query("Authorization") // 从 URL 参数获取
		} else {
			// 是普通 HTTP 请求
			token = c.Get("Authorization") // 从 Header 获取
			if token == "" || !strings.HasPrefix(token, config.Get("env.AUTHORIZATION_PREFIX").(string)) {
				return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
					"status": 500,
					"msg":    "请重新登录",
				})
			}
			// 去掉前缀
			token = strings.TrimPrefix(token, config.Get("env.AUTHORIZATION_PREFIX").(string))
		}
		// 查询 Redis 中的用户信息
		strUserinfo, err := RDB.Get(c.Context(), config.Get("env.AUTHORIZATION_PREFIX").(string)+token).Result()
		if err != nil {
			return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
				"status": 500,
				"msg":    "请重新登录",
			})
		}

		// 解析 JSON 字符串为对象
		var userInfo dao.User
		if err := json.Unmarshal([]byte(strUserinfo), &userInfo); err != nil {
			return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
				"status": 500,
				"msg":    "用户信息解析失败",
			})
		}
		// 刷新过期时间
		err = RDB.Expire(c.Context(), config.Get("env.AUTHORIZATION_PREFIX").(string)+token, time.Duration(config.Get("env.AUTHORIZATION_EXPIRE").(int64)*int64(time.Second))).Err()
		if err != nil {
			log.Println("Redis expire error:", err)
		}

		// 将 userInfo 放入 fiber context 的 locals 中
		c.Locals(common.ContextUserKey, userInfo)
		// 继续后续处理
		return c.Next()
	}
}

func DeviceMiddleware(config *toml.Tree) func(c *fiber.Ctx) error {
	return func(c *fiber.Ctx) error {
		deviceId := c.Query("DeviceId") // 从 URL 参数获取
		// 将 deviceId 放入 fiber context 的 locals 中
		c.Locals(common.ContextDeviceId, deviceId)
		// 继续后续处理
		return c.Next()
	}
}

func BrowserMiddleware(config *toml.Tree) func(c *fiber.Ctx) error {
	return func(c *fiber.Ctx) error {
		browserId := c.Query("BrowserId")
		if browserId == "" {
			return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
				"status": 500,
				"msg":    "缺少关键信息",
			})
		}
		// 将 deviceId 放入 fiber context 的 locals 中
		c.Locals(common.ContextBrowserId, browserId)
		// 继续后续处理
		return c.Next()
	}
}
